package com.classic.common;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 类描述：  一个方便在多种状态切换的view
 * <p>
 * 创建人:   续写经典
 * 创建时间: 2016/1/15 10:20.
 */
@SuppressWarnings("unused")
public class MultipleStatusView extends DependentLayout implements Component.BindStateChangedListener {
    private static final String TAG = "MultipleStatusView";
    private static final String VIEW_EMPTY = "emptyView";
    private static final String VIEW_ERROR = "errorView";
    private static final String VIEW_LOADING = "loadingView";
    private static final String VIEW_NETWORK = "noNetworkView";
    private static final String VIEW_CONTENT = "contentView";
    private static final LayoutConfig DEFAULT_LAYOUT_PARAMS =
            new LayoutConfig(LayoutConfig.MATCH_PARENT,
                    LayoutConfig.MATCH_PARENT);
    public static final int STATUS_CONTENT = 0x00;
    public static final int STATUS_LOADING = 0x01;
    public static final int STATUS_EMPTY = 0x02;
    public static final int STATUS_ERROR = 0x03;
    public static final int STATUS_NO_NETWORK = 0x04;
    private static final int NULL_RESOURCE_ID = -1;
    private Component mEmptyView;
    private Component mErrorView;
    private Component mLoadingView;
    private Component mNoNetworkView;
    private Component mContentView;
    private int mEmptyViewResId = ResourceTable.Layout_empty_view;
    private int mErrorViewResId = ResourceTable.Layout_error_view;
    private int mLoadingViewResId = ResourceTable.Layout_loading_view;
    private int mNoNetworkViewResId = ResourceTable.Layout_no_network_view;
    private int mContentViewResId = NULL_RESOURCE_ID;
    private int mViewStatus = -1;
    private int mhintResId = -1;
    private LayoutScatter mInflater;
    private ClickedListener mOnRetryClickListener;
    private OnViewStatusChangeListener mViewStatusListener;
    private EventHandler handler;
    // 新增资源根目录id
    private static int xmlRootLayoutResId = -1;
    private int emptyResId = -1;
    private int errorResId = -1;
    private int networkResId = -1;

    private final ArrayList<Integer> mOtherIds = new ArrayList<>();

    public MultipleStatusView(Context context) {
        this(context, null);
    }

    public MultipleStatusView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public MultipleStatusView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, null);
        handler = new EventHandler(EventRunner.getMainEventRunner());
        if (null != attrs) {
            boolean isPresent = attrs.getAttr(VIEW_EMPTY).isPresent();
            String viewString = "";
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_EMPTY).get().getStringValue();
                if (viewString.contains(":")) {
                    mEmptyViewResId = Integer.parseInt(viewString.split(":")[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_CONTENT).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_CONTENT).get().getStringValue();
                if (viewString.contains(":")) {
                    mContentViewResId = Integer.parseInt(viewString.split(":")[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_ERROR).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_ERROR).get().getStringValue();
                if (viewString.contains(":")) {
                    mErrorViewResId = Integer.parseInt(viewString.split(":")[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_LOADING).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_LOADING).get().getStringValue();
                if (viewString.contains(":")) {
                    mLoadingViewResId = Integer.parseInt(viewString.split(":")[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_NETWORK).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_NETWORK).get().getStringValue();
                if (viewString.contains(":")) {
                    mNoNetworkViewResId = Integer.parseInt(viewString.split(":")[1]);
                }
            }
        }
        mInflater = LayoutScatter.getInstance(getContext());
        setBindStateChangedListener(this);
        onFinishInflate();
    }

    private void onFinishInflate(){
        showContent();
    }

    /**
     * 获取当前状态
     *
     * @return 视图状态
     */
    public int getViewStatus() {
        return mViewStatus;
    }

    /**
     * 设置重试点击事件
     *
     * @param onRetryClickListener 重试点击事件
     */
    public void setOnRetryClickListener(ClickedListener onRetryClickListener) {
        this.mOnRetryClickListener = onRetryClickListener;
    }

    public void setEmptyResId(int resId) {
        emptyResId = resId;
    }

    /**
     * 显示空视图
     */
    public final void showEmpty() {
        showEmpty(mEmptyViewResId, DEFAULT_LAYOUT_PARAMS);
    }

    /**
     * 显示空视图
     *
     * @param hintResId  自定义提示文本内容
     * @param formatArgs 占位符参数
     */
    public final void showEmpty(int hintResId, Object... formatArgs) {
        showEmpty();
        setStatusHintContent(mEmptyView, hintResId, formatArgs);
    }

    /**
     * 显示空视图
     *
     * @param hint 自定义提示文本内容
     */
    public final void showEmpty(String hint) {
        showEmpty();
        setStatusHintContent(mEmptyView, hint);
    }

    /**
     * 显示空视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showEmpty(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showEmpty(null == mEmptyView ? inflateView(layoutId) : mEmptyView, layoutParams);
    }

    /**
     * 显示空视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showEmpty(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Empty view is null.");
        checkNull(layoutParams, "Layout params is null.");
        if (emptyResId == -1) {
            throw new NullPointerException("emptyResId is invalid,ues setEmptyResId(int resId)");
        }
        changeViewStatus(STATUS_EMPTY);
        if (null == mEmptyView) {
            mEmptyView = view;
            Component emptyRetryView = mEmptyView.findComponentById(emptyResId);
            if (null != mOnRetryClickListener && null != emptyRetryView) {
                emptyRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mEmptyView.getId());
            addComponent(mEmptyView, 0, layoutParams);
        }
        showViewById(mEmptyView.getId());
    }

    public void setErrorResId(int resId) {
        errorResId = resId;
    }

    /**
     * 显示错误视图
     */
    public final void showError() {
        showError(mErrorViewResId, DEFAULT_LAYOUT_PARAMS);
    }

    /**
     * 显示错误视图
     *
     * @param hintResId  自定义提示文本内容
     * @param formatArgs 占位符参数
     */
    public final void showError(int hintResId, Object... formatArgs) {
        showError();
        setStatusHintContent(mErrorView, hintResId, formatArgs);
    }

    /**
     * 显示错误视图
     *
     * @param hint 自定义提示文本内容
     */
    public final void showError(String hint) {
        showError();
        setStatusHintContent(mErrorView, hint);
    }

    /**
     * 显示错误视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showError(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showError(null == mErrorView ? inflateView(layoutId) : mErrorView, layoutParams);
    }

    /**
     * 显示错误视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showError(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Error view is null.");
        checkNull(layoutParams, "Layout params is null.");
        if (errorResId == -1) {
            throw new NullPointerException("errorResId is invalid,ues setErrorResId(int resId)");
        }
        changeViewStatus(STATUS_ERROR);
        if (null == mErrorView) {
            mErrorView = view;
            Component errorRetryView = mErrorView.findComponentById(errorResId);
            if (null != mOnRetryClickListener && null != errorRetryView) {
                errorRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mErrorView.getId());
            addComponent(mErrorView, 0, layoutParams);
        }
        showViewById(mErrorView.getId());
    }

    /**
     * 显示加载中视图
     */
    public final void showLoading() {
        showLoading(mLoadingViewResId, DEFAULT_LAYOUT_PARAMS);
    }

    /**
     * 显示加载中视图
     *
     * @param hintResId  自定义提示文本内容
     * @param formatArgs 占位符参数
     */
    public final void showLoading(int hintResId, Object... formatArgs) {
        showLoading();
        setStatusHintContent(mLoadingView, hintResId, formatArgs);
    }

    /**
     * 显示加载中视图
     *
     * @param hint 自定义提示文本内容
     */
    public final void showLoading(String hint) {
        showLoading();
        setStatusHintContent(mLoadingView, hint);
    }

    /**
     * 显示加载中视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showLoading(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showLoading(null == mLoadingView ? inflateView(layoutId) : mLoadingView, layoutParams);
    }

    /**
     * 显示加载中视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showLoading(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Loading view is null.");
        checkNull(layoutParams, "Layout params is null.");
        changeViewStatus(STATUS_LOADING);
        if (null == mLoadingView) {
            mLoadingView = view;
            mOtherIds.add(mLoadingView.getId());
            addComponent(mLoadingView, 0, layoutParams);
        }
        showViewById(mLoadingView.getId());
    }

    public void setNetWorkResId(int resId) {
        networkResId = resId;
    }

    /**
     * 显示无网络视图
     */
    public final void showNoNetwork() {
        showNoNetwork(mNoNetworkViewResId, DEFAULT_LAYOUT_PARAMS);
    }

    /**
     * 显示无网络视图
     *
     * @param hintResId  自定义提示文本内容
     * @param formatArgs 占位符参数
     */
    public final void showNoNetwork(int hintResId, Object... formatArgs) {
        showNoNetwork();
        setStatusHintContent(mNoNetworkView, hintResId, formatArgs);
    }

    /**
     * 显示无网络视图
     *
     * @param hint 自定义提示文本内容
     */
    public final void showNoNetwork(String hint) {
        showNoNetwork();
        setStatusHintContent(mNoNetworkView, hint);
    }

    /**
     * 显示无网络视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showNoNetwork(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showNoNetwork(null == mNoNetworkView ? inflateView(layoutId) : mNoNetworkView, layoutParams);
    }

    /**
     * 显示无网络视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showNoNetwork(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "No network view is null.");
        checkNull(layoutParams, "Layout params is null.");
        if (networkResId == -1) {
            throw new NullPointerException("networkResId is invalid,ues setNetWorkResId(int resId)");
        }
        changeViewStatus(STATUS_NO_NETWORK);
        if (null == mNoNetworkView) {
            mNoNetworkView = view;
            Component noNetworkRetryView = mNoNetworkView.findComponentById(networkResId);
            if (null != mOnRetryClickListener && null != noNetworkRetryView) {
                noNetworkRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mNoNetworkView.getId());
            addComponent(mNoNetworkView, 0, layoutParams);
        }
        showViewById(mNoNetworkView.getId());
    }

    /**
     * 显示内容视图
     */
    public final void showContent() {
        changeViewStatus(STATUS_CONTENT);
        if (null == mContentView && mContentViewResId != NULL_RESOURCE_ID) {
            mContentView = mInflater.parse(mContentViewResId, null, false);
            addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
        }
        showContentView();
    }

    /**
     * 显示内容视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showContent(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showContent(inflateView(layoutId), layoutParams);
    }

    /**
     * 显示内容视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showContent(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Content view is null.");
        checkNull(layoutParams, "Layout params is null.");
        changeViewStatus(STATUS_CONTENT);
        clear(mContentView);
        mContentView = view;
        addComponent(mContentView, 0, layoutParams);
        showViewById(mContentView.getId());
    }

    private void setStatusHintContent(Component view, int resId, Object... formatArgs) {
        checkNull(view, "Target view is null.");
        setStatusHintContent(view, view.getContext().getString(resId, formatArgs));
    }

    public void setStatusHintRes(int hintRes) {
        mhintResId = hintRes;
    }

    private void setStatusHintContent(Component view, String hint) {
        checkNull(view, "Target view is null.");
        if (mhintResId != -1) {
            Text hintView = (Text) view.findComponentById(mhintResId);
            if (null != hintView) {
                hintView.setText(hint);
            } else {
                throw new NullPointerException("Not find the view ID status hint content");
            }

        } else {
            throw new NullPointerException("Hint view is not set,use setStatusHintRes(int hintRes)");
        }
    }

    private Component inflateView(int layoutId) {
        return mInflater.parse(layoutId, null, false);
    }

    private void showViewById(int viewId) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            Component view = getComponentAt(i);
            view.setVisibility(view.getId() == viewId ? Component.VISIBLE : Component.HIDE);
        }
    }

    private void showContentView() {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            Component view = getComponentAt(i);
            view.setVisibility(mOtherIds.contains(view.getId()) ? Component.HIDE : Component.VISIBLE);
        }
    }

    private void checkNull(Object object, String hint) {
        if (null == object) {
            throw new NullPointerException(hint);
        }
    }

    private void clear(Component... views) {
        if (null == views) {
            return;
        }
        try {
            for (Component view : views) {
                if (null != view) {
                    removeComponent(view);
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(MultipleStatusView.class.getName()).log(Level.SEVERE, ex.getMessage());
        }
    }

    @Override
    public void onComponentBoundToWindow(Component component) {

    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        clear(mEmptyView, mLoadingView, mErrorView, mNoNetworkView);
        if (!mOtherIds.isEmpty()) {
            mOtherIds.clear();
        }
        if (null != mOnRetryClickListener) {
            mOnRetryClickListener = null;
        }
        if (null != mViewStatusListener) {
            mViewStatusListener = null;
        }
    }

    /**
     * 视图状态改变接口
     */
    public interface OnViewStatusChangeListener {

        /**
         * 视图状态改变时回调
         *
         * @param oldViewStatus 之前的视图状态
         * @param newViewStatus 新的视图状态
         */
        void onChange(int oldViewStatus, int newViewStatus);
    }

    /**
     * 设置视图状态改变监听事件
     *
     * @param onViewStatusChangeListener 视图状态改变监听事件
     */
    public void setOnViewStatusChangeListener(OnViewStatusChangeListener onViewStatusChangeListener) {
        this.mViewStatusListener = onViewStatusChangeListener;
    }

    /**
     * 改变视图状态
     *
     * @param newViewStatus 新的视图状态
     */
    private void changeViewStatus(int newViewStatus) {
        if (mViewStatus == newViewStatus) {
            return;
        }
        if (null != mViewStatusListener) {
            mViewStatusListener.onChange(mViewStatus, newViewStatus);
        }
        mViewStatus = newViewStatus;
    }


    private void setContentViewResId(int contentViewResId) {
        this.mContentViewResId = contentViewResId;
        this.mContentView = mInflater.parse(mContentViewResId, null, false);
        addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
    }

    private void setContentView(ComponentContainer contentView) {
        this.mContentView = contentView;
        addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
    }

    public static MultipleStatusView attach(Fraction fraction, int rootAnchor) {
        if (xmlRootLayoutResId == -1) {
            throw new NullPointerException("xmlRootLayoutResId is invalid,use setXmlRootLayoutResId(int rootId)");
        }
        if (-1 != rootAnchor) {
            ComponentContainer contentAnchor = (ComponentContainer) fraction.getComponent().findComponentById(xmlRootLayoutResId);
            if (null != contentAnchor) {
                attach(contentAnchor);
            }
        }
        ComponentContainer defaultAnchor = (ComponentContainer) fraction.getComponent().findComponentById(xmlRootLayoutResId);
        return attach(defaultAnchor);
    }

    public static MultipleStatusView attach(Ability activity, int rootAnchor) {
        if (xmlRootLayoutResId == -1) {
            throw new NullPointerException("xmlRootLayoutResId is invalid,use setXmlRootLayoutResId(int rootId)");
        }
        if (-1 != rootAnchor) {
            ComponentContainer contentAnchor = (ComponentContainer) activity.findComponentById(rootAnchor);
            if (null != contentAnchor) {
                attach(contentAnchor);
            }
        }
        ComponentContainer defaultAnchor = (ComponentContainer) activity.findComponentById(xmlRootLayoutResId);
        return attach(defaultAnchor);
    }

    public static MultipleStatusView attach(ComponentContainer rootAnchor) {
        if (null == rootAnchor) {
            throw new IllegalArgumentException("root Anchor Component can't be null");
        }
        ComponentContainer parent = (ComponentContainer) rootAnchor.getComponentParent();
        int anchorIndex = parent.getChildIndex(rootAnchor);
        if (-1 != anchorIndex) {
            parent.removeComponent(rootAnchor);
            MultipleStatusView statusView = new MultipleStatusView(rootAnchor.getContext());
            statusView.setContentView(rootAnchor);
            ComponentContainer.LayoutConfig config = rootAnchor.getLayoutConfig();
            parent.addComponent(statusView, anchorIndex, config);
            return statusView;
        }
        return null;
    }

    public void setXmlRootLayoutResId(int rootId) {
        xmlRootLayoutResId = rootId;
    }

    public void removeCallbacks(Runnable runnable) {
        handler.removeTask(runnable);
    }

    public void postDelayed(Runnable runnable, int delay) {
        handler.postTask(runnable, delay);
    }
}
